#include <dirent.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#include "directory.h"

static int exsit(const char *pathname);
static int is_dir(const char *pathname);
int exsit(const char *pathname) { return !access(pathname, F_OK); }
int is_dir(const char *pathname) {
  struct stat sb;
  stat(pathname, &sb);
  return (sb.st_mode & S_IFMT) == S_IFDIR;
}
int cd(const char *path, const char *cwd, char *output) {
  if (exsit(path) && is_dir(path)) {
    sprintf(output, "%s%s%s", cwd, "/", path);
    return 0;
  } else {
    sprintf(output, "no such directory: %s", path);
    return -1;
  }
}

static void file_type(mode_t mode, char *type);
static void file_type(mode_t mode, char *type) {
  switch (mode & S_IFMT) {
  case S_IFBLK:
    type[0] = 'b';
    break;
  case S_IFCHR:
    type[0] = 'c';
    break;
  case S_IFDIR:
    type[0] = 'd';
    break;
  case S_IFIFO:
    type[0] = 'p';
    break;
  case S_IFLNK:
    type[0] = 'l';
    break;
  case S_IFREG:
    type[0] = '-';
    break;
  case S_IFSOCK:
    type[0] = 's';
    break;
  default:
    type[0] = '?';
    break;
  }

  int mask = 1;
  int idx = 9;

  const char *cmp[] = {"----------", "-rwxrwxrwx"};

  for (int i = 9; i > 0; --i) {
    type[i] = cmp[!!(mode & mask)][i];
    mask <<= 1;
  }
  type[10] = 0;
}

int ls(const char *name, char *output) {
  bzero(output, 4096);
  const char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
                         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

  DIR *dirp = opendir(name);
  if (!dirp) {
    strcpy(output, strerror(errno));
    return -1;
  }

  struct dirent *direntp;
  char new_pathname[1024] = {0};
  char type[1024] = {0};

  bzero(output, 1024);
  char info[1024] = {0};
  while ((direntp = readdir(dirp))) {
    struct stat buf;

    sprintf(new_pathname, "%s%s%s", name, "/", direntp->d_name);
    int ret = stat(new_pathname, &buf);
    if (ret == -1) {
      perror("stat");
    }

    struct tm *ptm = localtime(&buf.st_mtime);
    file_type(buf.st_mode, type);

    bzero(info, sizeof(info));
    sprintf(info, "%s %4ld %10s %10s %-8ld %s %02d %02d %02d %s\n", type,
            buf.st_nlink, getpwuid(buf.st_uid)->pw_name,
            getgrgid(buf.st_gid)->gr_name, buf.st_size, month[ptm->tm_mon],

            ptm->tm_mday, ptm->tm_hour, ptm->tm_min, direntp->d_name);
    printf("%s\n", info);
    strcat(output, info);
  }
  /* opendir(name); */
  /* DIR *dirp = opendir(name); */
  /* *output = *name; */
  /* strcat(output, "\n"); */
  /* struct dirent *direntp; */
  /* long loc; */
  /* while ((direntp = readdir(dirp)) != NULL) { */
  /*   if (strcmp(direntp->d_name, "..") == 0 || strcmp(direntp->d_name, ".") ==
   * 0) */
  /*     continue; */
  /*   strcat(output, direntp->d_name); */
  /*   strcat(output, "\n"); */
  /* } */
  /* rewinddir(dirp); */
  printf("\noutput = %s\n", output);

  closedir(dirp);
  return 0;
}

int pwd(char *output) {
  bzero(output, 1024);
  char *p = getcwd(NULL, 0);
  if (!p) {
    strcpy(output, strerror(errno));
    return -1;
  }

  strcpy(output, p);
  return 0;
}

int create_directory(const char *pathname, mode_t mode, char *output) {
  bzero(output, 1024);
  int ret = mkdir(pathname, 0777);
  if (ret == -1) {
    strcpy(output, strerror(errno));
    return -1;
  }

  sprintf(output, "create directory: %s", pathname);
  return 0;
}

int remove_directory(const char *pathname, char *output) {
  bzero(output, 1024);
  int ret = rmdir(pathname);
  if (ret == -1) {
    strcpy(output, strerror(errno));
    return -1;
  }

  sprintf(output, "remove directory: %s", pathname);
  return 0;
}

int remove_file(const char *pathname, char *output) {
  bzero(output, 1024);
  int ret = unlink(pathname);
  if (ret == -1) {
    strcpy(output, strerror(errno));
    return -1;
  }

  sprintf(output, "remove file: %s", pathname);
  return 0;
}
